#ifndef tpt1_h
#define tpt1_h

// this header needs
#include "smg.h"

// TPT1 section of BTP files of Super Mario Galaxy

// structure
// magic - 32 bits ("TPT1" or "1TPT")
// size - 32 bits
// loop_mode - 8 bits (from 0 - 4)
// unknown1 - 8 bits (always 0xFF?)
// anim_length - 16 bits
// mat_count - 16 bits
// tex_indexes_length - 16 bits
// mat_anim_data_offset - 32 bits (always 0x00000020?)
// tex_indexes_offset - 32 bits
// mat_indexes_offset - 32 bits
// mat_names_offset - 32 bits
// --- repeated mat_count times
//   length - 16 bits 
//   index - 16 bits 
//   unknown2 - 16 bits (always 0x00FF?)
//   unknown3 - 16 bits (always 0xFFFF?) 
// --- end
// --- repeated tex_indexes_length times
//   tex_indexes - 16 bits
// --- end
// pad1 - aligned to multiple of 4 byte position (respect to TPT1 section start)
// --- repeated mat_count times
//   mat_indexes - 16 bits
// --- end
// pad2 - aligned to multiple of 4 byte position (respect to TPT1 section start)
// mat_names - (sizeof(this_name_table))
// pad3 - aligned to multiple of 32 byte position (respect to TPT1 section start)

// main information (most relevant information)
typedef struct {                      // size on binary file
  owl_byte loop_mode;                 // 8bits
  owl_umax anim_length;               // 16bits
  owl_umax mat_count;                 // 16bits
  owl_umax tex_indexes_length;        // 16bits
  struct owl_smg_tpt1_mat_anim_data_main {    
    owl_umax length;                  // 16bits
    owl_umax index;                   // 16bits
  } * mat_anim_data_main;             // (2 * 16bits) * mat_count
  owl_umax * tex_indexes;             // seems to always correspond to 16bits * tex_indexes_length
  owl_umax * mat_indexes;             // 16bits * mat_count
  owl_smg_name_table * mat_names;     // (2 * 16 bits * (mat_count + 1)) + size of all string names
} owl_smg_tpt1_main;

// extra information (can be determined from main information)
typedef struct {                 // size on binary file
  owl_umax magic;                // 32bits ("TPT1" or "1TPT")
  owl_umax size;                 // 32bits
  owl_byte unknown1;             // 8bits (seems to be always 0xFF)
  owl_umax mat_anim_data_offset; // 32bits
  owl_umax tex_indexes_offset;   // 32bits
  owl_umax mat_indexes_offset;   // 32bits
  owl_umax mat_names_offset;     // 32bits
  struct owl_smg_tpt1_mat_anim_data_extra {
    owl_umax unknown2;           // 32bits (seems to be always 0x00FFFFFF)
  } * mat_anim_data_extra;       // (32 bits) * mat_count
  owl_byte pad1_size;            // aligns the next data to the next 4 byte position multiple
  owl_byte pad2_size;            // aligns the next data to the next 4 byte position multiple
  owl_byte pad3_size;            // aligns the next data to the next 32 byte position multiple
} owl_smg_tpt1_extra;

// the actual structure
typedef struct {
  owl_smg_tpt1_main * main;
  owl_smg_tpt1_extra * ext;
} owl_smg_tpt1;

// enum with the possible codes a TPT1 section will present while analizing it
// all errors are named to indicate the place of the read error (in the best case)
// codes ending in 1 mean that are errors that come from analizing a TPT1 section alone
// codes ending with 2 are errors that come from analizing the section agaisnt the sections from a BMD/BDL
// other errors are related to logic errors when reading the raw string
typedef enum
{
  OWL_SMG_TPT1_ERR_ALL_GOOD,
  
  OWL_SMG_TPT1_ERR_FUNC_PARAMS,
  OWL_SMG_TPT1_ERR_STR_SIZE,
  OWL_SMG_TPT1_ERR_MEM_ALLOC,
  
  OWL_SMG_TPT1_ERR_MAGIC_1,
  OWL_SMG_TPT1_ERR_SIZE_1,
  OWL_SMG_TPT1_ERR_LOOP_MODE_1,
  OWL_SMG_TPT1_ERR_UNKNOWN1_1,
  OWL_SMG_TPT1_ERR_TEX_INDEXES_LENGTH_1,
  OWL_SMG_TPT1_ERR_TPT1_OFFSET_1,
  OWL_SMG_TPT1_ERR_TEX_INDEXES_OFFSET_1,
  OWL_SMG_TPT1_ERR_MAT_INDEXES_OFFSET_1,
  OWL_SMG_TPT1_ERR_MAT_NAMES_OFFSET_1,
  OWL_SMG_TPT1_ERR_MAT_ANIM_LENGTH_1,
  OWL_SMG_TPT1_ERR_MAT_ANIM_INDEX_1,
  OWL_SMG_TPT1_ERR_MAT_ANIM_UNKNOWN2_1,
  OWL_SMG_TPT1_ERR_MAT_ANIM_UNKNOWN3_1,
  OWL_SMG_TPT1_ERR_TEX_INDEXES_1,
  OWL_SMG_TPT1_ERR_PAD1_1,
  OWL_SMG_TPT1_ERR_MAT_INDEXES_1,
  OWL_SMG_TPT1_ERR_PAD2_1,
  OWL_SMG_TPT1_ERR_MAT_NAMES_1,
  OWL_SMG_TPT1_ERR_PAD3_1,
  
  OWL_SMG_TPT1_ERR_MAT_COUNT_2,
  OWL_SMG_TPT1_ERR_TEX_INDEXES_2,
  OWL_SMG_TPT1_ERR_MAT_INDEXES_2,
  OWL_SMG_TPT1_ERR_MAT_NAMES_2,
  
  OWL_SMG_TPT1_ERR_LIMIT,
} owl_smg_tpt1_err_cd;

// global variable for the owl_create_smg_tpt1()
// function used by the owl_get_err_cd_smg_tpt1()
owl_smg_tpt1_err_cd OWL_SMG_TPT1_ERR_CD = OWL_SMG_TPT1_ERR_ALL_GOOD;
owl_umax OWL_SMG_TPT1_ERR_READ_POS = 0;

// tpt1 constants
#define OWL_SMG_TPT1_UNKNOWN1 0xFF
#define OWL_SMG_TPT1_UNKNOWN2 0x00FFFFFF
#define OWL_SMG_TPT1_MAT_ANIM_DATA_OFFSET 0x20
#define OWL_SMG_TPT1_MAGIC_LENGTH 4
owl_umax OWL_SMG_TPT1_MAGIC[][2] = {{0x54505431, 0x31545054}}; // "TPT1", "1TPT" (int form, easier for checks)

// basic functions
owl_bool owl_check_smg_tpt1_main_pointer(owl_byte * src, owl_umax size);
owl_bool owl_check_smg_tpt1_ext_pointer(owl_byte * src, owl_umax size);
owl_bool owl_check_smg_tpt1_pointer(owl_byte * src, owl_umax size);
owl_bool owl_check_smg_tpt1_main_members(owl_byte loop_mode,
                                         owl_umax anim_length,
                                         owl_umax mat_count,
                                         owl_umax tex_indexes_length,
                                         struct owl_smg_tpt1_mat_anim_data_main * mat_anim_data,
                                         owl_umax * tex_indexes,
                                         owl_umax * mat_indexes,
                                         owl_smg_name_table * mat_names);
owl_bool owl_check_smg_tpt1_main_all(owl_smg_tpt1_main * main, owl_umax size);
owl_bool owl_check_smg_tpt1_all(owl_smg_tpt1 * tpt1, owl_umax size);
owl_smg_tpt1 * owl_create_smg_tpt1(owl_str * raw, owl_endian endian);
owl_umax owl_free_smg_tpt1(owl_smg_tpt1 * tpt1);
owl_umax owl_print_smg_tpt1(owl_byte * src, owl_umax size);
owl_char owl_comp_smg_tpt1(owl_byte * tpt11, owl_byte * tpt12);

// specific functions
owl_bool owl_get_smg_tpt1_extra(owl_smg_tpt1 * tpt1);
owl_umax owl_get_smg_tpt1_bin_size(owl_smg_tpt1 * tpt1);
owl_smg_tpt1_err_cd owl_get_err_cd_smg_tpt1(owl_str * raw, owl_endian endian);
owl_smg_tpt1 * owl_get_smg_tpt1_min_args(owl_byte loop_mode,
                                         owl_umax anim_length,
                                         owl_umax mat_count,
                                         owl_umax tex_indexes_length,
                                         struct owl_smg_tpt1_mat_anim_data_main * mat_anim_data_main,
                                         owl_umax * tex_indexes,
                                         owl_umax * mat_indexes,
                                         owl_str ** mat_names);
owl_str * owl_get_smg_tpt1_as_str(owl_smg_tpt1 * tpt1, owl_endian endian);

//~ owl_smg_tpt1 * owl_force_create_smg_tpt1(owl_str * raw); // only ignores soft errors
//~ owl_bool owl_check_smg_tpt1_vs_mat3_tex1(owl_smg_tpt1 * tpt1, void * mat3, void * tex1);

#include "tpt1.c"

#endif // tpt1_h
